package com.dollar.juc.threadLocal.simpleDateFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * https://www.jianshu.com/p/5a7a88e62309
 * SimpleDateFormat 在多线程场景下可能出现问题：
 * Exception in thread "pool-1-thread-2" java.lang.NumberFormatException: multiple points
 * 原因如下：
 * SimpleDateFormat是继承自DateFormat类，DateFormat类中维护了一个全局的Calendar变量。
 * 从注释可以看出，这个Calendar对象既用于格式化也用于解析日期时间。再查看parse()方法接近最后的部分。
 * 可见，最后的返回值是通过调用CalendarBuilder.establish()方法获得的，而它的入参正好就是前面的Calendar对象。
 * 该方法中先后调用了cal.clear()与cal.set()，也就是先清除cal对象中设置的值，再重新设置新的值。
 * 由于Calendar内部并没有线程安全机制，并且这两个操作也都不是原子性的，所以当多个线程同时操作一个
 * SimpleDateFormat时就会引起cal的值混乱。类似地，format()方法也存在同样的问题。
 */
public class SimpleDateFormatExample {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        // 创建线程池，最好直接new ThreadPoolExecutor，而不是用Executors工具类
        // ExecutorService threadPool = Executors.newCachedThreadPool();
        ExecutorService threadPool = new ThreadPoolExecutor(
                5, 50, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100)
        );

        List<String> dates = Arrays.asList(
                "2019-02-21 15:47:01",
                "2018-03-22 16:46:02",
                "2017-04-23 17:45:03",
                "2016-05-24 18:44:04",
                "2015-06-25 19:43:05",
                "2014-07-26 20:42:06",
                "2013-08-27 21:41:07",
                "2012-09-28 22:40:08",
                "2011-10-29 23:39:09"
        );

        for (String date : dates) {
            threadPool.execute(() -> {
                try {
                    System.out.println(simpleDateFormat.parse(date));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}


